﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RadioPlayer.cs" company="">
//   
// </copyright>
// <summary>
//   The radio player state.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace TinyRadio.UserInterface.Models
{
    using System;
    using System.ComponentModel;

    using TinyRadio.Models;
    using TinyRadio.UserInterface.Infrastructure;

    using WMPLib;

    /// <summary>The radio player state.</summary>
    public enum RadioPlayerState
    {
        /// <summary>The undefined.</summary>
        Undefined, 

        /// <summary>The stopped.</summary>
        Stopped, 

        /// <summary>The paused.</summary>
        Paused, 

        /// <summary>The playing.</summary>
        Playing, 

        /// <summary>The scan forward.</summary>
        ScanForward, 

        /// <summary>The scan reverse.</summary>
        ScanReverse, 

        /// <summary>The buffering.</summary>
        Buffering, 

        /// <summary>The waiting.</summary>
        Waiting, 

        /// <summary>The media ended.</summary>
        MediaEnded, 

        /// <summary>The transitioning.</summary>
        Transitioning, 

        /// <summary>The ready.</summary>
        Ready, 

        /// <summary>The reconnecting.</summary>
        Reconnecting
    }

    /// <summary>The radio player.</summary>
    public class RadioPlayer : IRadioPlayer, INotifyPropertyChanged
    {
        #region Fields

        /// <summary>The _media player.</summary>
        private readonly WindowsMediaPlayer _mediaPlayer;

        #endregion

        #region Constructors and Destructors

        /// <summary>Initializes a new instance of the <see cref="RadioPlayer"/> class.</summary>
        public RadioPlayer()
        {
            this._mediaPlayer = new WindowsMediaPlayer { uiMode = "invisible" };

            this._mediaPlayer.PlayStateChange += (newState) =>
                {
                    this.State = ParseState(newState);

                    if (this.StateChanged != null)
                    {
                        this.StateChanged(this, new EventArgs<RadioPlayerState>(this.State));
                    }
                };
        }

        #endregion

        #region Public Events

        /// <summary>The property changed.</summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>The state changed.</summary>
        public event EventHandler<EventArgs<RadioPlayerState>> StateChanged;

        #endregion

        #region Public Properties

        /// <summary>Gets a value indicating whether can pause.</summary>
        public bool CanPause
        {
            get
            {
                return this._mediaPlayer.controls.isAvailable["pause"];
            }
        }

        /// <summary>Gets or sets the state.</summary>
        public RadioPlayerState State { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>The pause.</summary>
        public void Pause()
        {
            if (this._mediaPlayer != null)
            {
                this._mediaPlayer.controls.pause();
            }
        }

        /// <summary>The play.</summary>
        public void Play()
        {
            if (this._mediaPlayer != null)
            {
                this._mediaPlayer.controls.play();
            }
        }

        /// <summary>The play.</summary>
        /// <param name="radioStation">The radio station.</param>
        public void Play(RadioStation radioStation)
        {
            if (this._mediaPlayer == null)
            {
                return;
            }

            this._mediaPlayer.URL = radioStation.Url;

            this._mediaPlayer.controls.play();
        }

        /// <summary>The set volume level.</summary>
        /// <param name="level">The level.</param>
        public void SetVolumeLevel(int level)
        {
            if (this._mediaPlayer != null)
            {
                this._mediaPlayer.settings.volume = level;
            }
        }

        /// <summary>The stop.</summary>
        public void Stop()
        {
            if (this._mediaPlayer != null)
            {
                this._mediaPlayer.controls.stop();
            }
        }

        #endregion

        #region Methods

        /// <summary>The parse state.</summary>
        /// <param name="state">The state.</param>
        /// <returns>The <see cref="RadioPlayerState"/>.</returns>
        private static RadioPlayerState ParseState(int state)
        {
            switch (state)
            {
                case 1:
                    return RadioPlayerState.Stopped;
                case 2:
                    return RadioPlayerState.Paused;
                case 3:
                    return RadioPlayerState.Playing;
                case 4:
                    return RadioPlayerState.ScanForward;
                case 5:
                    return RadioPlayerState.ScanReverse;
                case 6:
                    return RadioPlayerState.Buffering;
                case 7:
                    return RadioPlayerState.Waiting;
                case 8:
                    return RadioPlayerState.MediaEnded;
                case 9:
                    return RadioPlayerState.Transitioning;
                case 10:
                    return RadioPlayerState.Ready;
                case 11:
                    return RadioPlayerState.Reconnecting;

                default:
                    return RadioPlayerState.Undefined;
            }
        }

        /// <summary>The raise property changed.</summary>
        /// <param name="propertyName">The property name.</param>
        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}